#include "cbuf.h"


#define fd2cbuf(fd)  ((CBuf *)fd)
#define cbuf2fd(cbuf)((int)cbuf)

static char *s_linebuf = NULL;
static int s_linebuf_len = 0;

int cbuf_info(int fd)
{
    CBuf *cbuf = fd2cbuf(fd);
    js_sys("cbuf", "%d/%d rptr:%d wptr:%d\n", cbuf_size(fd), cbuf_len(fd), cbuf->rptr, cbuf->wptr);
}
int cbuf_new(int initsize)
{
	CBuf *cbuf = (CBuf *)malloc(sizeof(CBuf));
	bzero(cbuf, sizeof(CBuf));

	//初始化
	cbuf->buf = (char *)malloc(initsize);
	cbuf->buf_len = initsize;

	return cbuf2fd(cbuf);
}
int cbuf_free(int fd){
    CBuf *cbuf = fd2cbuf(fd);
    free(cbuf->buf);
    return 1;
}
int cbuf_isfull(int fd)
{
	CBuf *cbuf = fd2cbuf(fd);
	return ((cbuf->rptr == cbuf->wptr + 1) ||
			(cbuf->rptr == 0 && cbuf->wptr == cbuf->buf_len - 1));
}

int cbuf_isempty(int fd)
{
	CBuf *cbuf = fd2cbuf(fd);
	return (cbuf->wptr == cbuf->rptr);
}

char* cbuf_base(int fd)
{
	CBuf *cbuf = fd2cbuf(fd);
	return cbuf->buf;
}

char *cbuf_rptr(int fd)
{
	CBuf *cbuf = fd2cbuf(fd);
	return (char *)(cbuf->buf + cbuf->rptr);
}

char *cbuf_wptr(int fd)
{
	CBuf *cbuf = fd2cbuf(fd);
	return cbuf->buf + cbuf->wptr;
}
int cbuf_rlen(int fd)
{
    CBuf *cbuf = fd2cbuf(fd);
    if(cbuf->rptr > cbuf->wptr)
	{
        return cbuf->buf_len - cbuf->rptr;		
	}else
	{
		return cbuf->wptr - cbuf->rptr;
	}
}
int cbuf_wlen(int fd)
{
	CBuf *cbuf = fd2cbuf(fd);
	if(cbuf->rptr > cbuf->wptr)
	{
		return cbuf->rptr - cbuf->wptr - 1;
	}else if(cbuf->rptr == 0)
	{
		return cbuf->buf_len - cbuf->wptr - 1;
	}else
    {
        return cbuf->buf_len - cbuf->wptr;
    }
}
int cbuf_len(int fd)
{
    CBuf *cbuf = fd2cbuf(fd);
    return cbuf->buf_len;
}
int cbuf_size(int fd)
{
	CBuf *cbuf = fd2cbuf(fd);
    if(cbuf->rptr > cbuf->wptr)
	{
        return cbuf->buf_len - cbuf->rptr + cbuf->wptr;		
	}else
	{
		return cbuf->wptr - cbuf->rptr;
	}
}
int cbuf_remain(int fd)
{
	CBuf *cbuf = fd2cbuf(fd);
	return cbuf->buf_len - cbuf_size(fd) - 1;
}
int cbuf_rskip(int fd, int buf_len)
{
    CBuf *cbuf = fd2cbuf(fd);
    int buf_remain = cbuf_size(fd);
    if(buf_remain < buf_len)
    {
        return 0;
    }
    int rlen = cbuf_rlen(fd);
    if(rlen < buf_len)
    {
        //分两段读
        rlen = buf_len - rlen;
        cbuf->rptr = rlen;
        cbuf->rptr %= cbuf->buf_len;
    }else
    {
        //直接读
        cbuf->rptr += buf_len;
        cbuf->rptr %= cbuf->buf_len;
    }
}
int cbuf_look(int fd, void *vbuf, int buf_len)
{
	int i;
    CBuf *cbuf = fd2cbuf(fd);
    int buf_remain = cbuf_size(fd);
    
    if(buf_remain < buf_len)
    {
        return 0;
    }
    char *buf = (char *)vbuf;
    char *rbuf = cbuf_rptr(fd);
    int rlen = cbuf_rlen(fd);
    if(rlen < buf_len)
    {
        //分两段读
        memcpy(buf,         rbuf,       rlen);
        memcpy(buf + rlen,  cbuf->buf,  buf_len - rlen);
    }else
    {
        //直接读
        memcpy(buf, rbuf, buf_len);
    }
    return 1;
}
int cbuf_look_int(int fd)
{
    int buf = 0;
    cbuf_look(fd, (char *)&buf, 4);
    return buf;
}
int cbuf_read(int fd, void *vbuf, int buf_len)
{
    CBuf *cbuf = fd2cbuf(fd);
    int buf_remain = cbuf_size(fd);
    if(buf_remain < buf_len)
    {
        return 0;
    }
    char *buf = (char *)vbuf;
    char *rbuf = cbuf_rptr(fd);
    int rlen = cbuf_rlen(fd);
    if(rlen < buf_len)
    {
        //分两段读
        memcpy(buf,         rbuf,       rlen);
        memcpy(buf + rlen,  cbuf->buf,  buf_len - rlen);
        cbuf->rptr = buf_len - rlen;
    }else
    {
        //直接读
        memcpy(buf, rbuf, buf_len);
        cbuf->rptr += buf_len;
        cbuf->rptr %= cbuf->buf_len;
    }
    return 1;
}
int cbuf_read_int(int fd)
{
    int val = 0;
    cbuf_read(fd, (char *)&val, sizeof(int));
    return val;
}
short cbuf_read_short(int fd)
{
    short val = 0;

    cbuf_read(fd, (char *)&val, sizeof(short));
    return val;
}
char cbuf_read_char(int fd)
{
    char val = 0;
    cbuf_read(fd, (char *)&val, sizeof(char));
    return val;
}
static char s_line_buf[1024];

const char *cbuf_read_utf(int fd)
{
    unsigned short len = 0;
    cbuf_read(fd, (char *)&len, sizeof(unsigned short));

    cbuf_read(fd, s_line_buf, len);
    s_line_buf[len] = '\0';
    cbuf_info(fd);
    return (const char *)s_line_buf;
}
int cbuf_wskip(int fd, int buf_len)
{
    CBuf *cbuf = fd2cbuf(fd);
    cbuf_ensure(fd, buf_len);
    
    int   wlen = cbuf_wlen(fd);
    if(wlen < buf_len)
    { 
        wlen = buf_len - wlen;
        cbuf->wptr = wlen;
        cbuf->wptr %= cbuf->buf_len;
    }else
    {
        cbuf->wptr += buf_len;
        cbuf->wptr %= cbuf->buf_len;
    } 
    return 1;
}
int cbuf_write_cbuf(int fd, int buffd, int buf_len){
	CBuf *cbuf = fd2cbuf(buffd);
	int rlen = cbuf_rlen(buffd);
	if(rlen >= buf_len){
		char *rbuf = cbuf_rptr(buffd);
		cbuf_write(fd, rbuf, buf_len);
	}else{/*rlen < buf_len*/
		//分两段复制
		char *rbuf = cbuf_rptr(buffd);
		cbuf_write(fd, rbuf, rlen);
		rlen = buf_len - rlen;
		rbuf = cbuf_base(fd);
		cbuf_write(fd, rbuf, rlen);
	}
	return 1;
}
int cbuf_set_wptr(int fd, char *wptr){
	CBuf *cbuf = fd2cbuf(fd);
	cbuf->wptr = wptr - cbuf->buf;
	return 1;
}
int cbuf_set_rptr(int fd, char *rptr){
	CBuf *cbuf = fd2cbuf(fd);
	cbuf->rptr = rptr - cbuf->buf;
	return 1;
}
int cbuf_write(int fd, const void *vbuf, int buf_len)
{
    CBuf *cbuf = fd2cbuf(fd);
    cbuf_ensure(fd, buf_len);
    char *buf = (char *)vbuf;
    char *wbuf = cbuf_wptr(fd);
    int   wlen = cbuf_wlen(fd);
    if(wlen < buf_len)
    {
        //分两段复制
        memcpy(wbuf,      buf, wlen);
        buf += wlen;
        wlen = buf_len - wlen;
        memcpy(cbuf->buf, buf, wlen);
        cbuf->wptr = wlen;
        cbuf->wptr %= cbuf->buf_len;
    }else
    {
        //直接复制
        memcpy(wbuf, buf, buf_len);
        cbuf->wptr += buf_len;
        cbuf->wptr %= cbuf->buf_len;
    }    
    return 1;
}
int cbuf_write_int(int fd, int val)
{
    return cbuf_write(fd, &val, sizeof(int));
}
int cbuf_write_short(int fd, short val)
{
    return cbuf_write(fd, &val, sizeof(short));
}
int cbuf_write_char(int fd, char val)
{
    return cbuf_write(fd, &val, sizeof(char));
}
int cbuf_write_utf(int fd, const char* val)
{
    cbuf_info(fd);
    short len = strlen(val);
    cbuf_write_short(fd, len); 
    cbuf_write(fd, val,  len); 
   
    js_sys("cbuf", "write str %s\n", val);
    cbuf_info(fd);
}
/**
 *  功能:整理成线性buf
**/
int cbuf_2line(int fd)
{
	CBuf *cbuf = fd2cbuf(fd);
	if(cbuf->wptr >= cbuf->rptr)
	{
		return 1;
	}
	int len_left = cbuf->wptr;
	int len_right = cbuf->buf_len - cbuf->rptr;
	char *buf_left = cbuf->buf;
	char *buf_right = cbuf->buf + cbuf->rptr;
    
    if(len_left > s_linebuf_len)
    {
        //确定临时buf足够长
        if(s_linebuf != NULL)
        {
            free(s_linebuf);
        }
        s_linebuf = (char*)malloc(len_left);
        s_linebuf_len = len_left;
    }
    
	memcpy(s_linebuf, 			  buf_left,   len_left);
	memcpy(cbuf->buf, 			  buf_right,  len_right);
	memcpy(cbuf->buf + len_right, s_linebuf,  len_left);
	cbuf->rptr = 0;
	cbuf->wptr = len_left + len_right;
}
int cbuf_double(int fd)
{
    CBuf *cbuf = fd2cbuf(fd);
    int buf_len = cbuf->buf_len;
    return cbuf_grow(fd, buf_len);
}
int cbuf_grow(int fd, int grow_size)
{
    CBuf *cbuf = fd2cbuf(fd);

    //整理成线性buf
    cbuf_2line(fd);
    //扩大buf
	int new_buf_len = cbuf->buf_len + grow_size;
	char *new_buf = (char*)realloc(cbuf->buf, new_buf_len);
    cbuf->buf = new_buf;
    cbuf->buf_len = new_buf_len;
    return 1;
}
int cbuf_ensure(int fd, int need_size)
{
	CBuf *cbuf = fd2cbuf(fd);
	int remain = cbuf_remain(fd);
	if(remain >= need_size)
	{
		return 1;
	}
    return cbuf_grow(fd, need_size);
}
